package server

import (
	"encoding/json"
	"fmt"
	global2 "longmen/server/config/global"
	"longmen/server/internal/services/nami/utils"
	"longmen/server/pkg/common/api_models"
	utils2 "longmen/server/pkg/common/helper/const"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"sort"
	"time"

	"gorm.io/gorm"
)

var expMap = map[int]int{
	1: 0,
	2: 0,
	3: 0,
	4: 0,
	5: 0,
	6: 0,
	7: 0,
}

const WEEKDAY = 7

/**
 * @author Jared
 * @description 初始化用户签到记录
 * @createTime 16:55 2022/10/22
 **/
func GenUserCheckin(uid int, checkin *models_main.UserCheckin) error {
	if checkin == nil || checkin.Uid <= 0 {
		checkin.Uid = uid
		checkin.Count = 0
		checkin.OrdNum = 1
		checkin.LastCheckStartTime = time.Time{}
		checkin.LastCheckTime = time.Time{}
		return db_main.InsertUserCheckin(checkin)
	}
	return nil
}

/**
 * @author Jared
 * @description 获取签到任务奖励
 * @createTime 16:54 2022/10/22
 **/
func GetCheckinTaskReward() (
	taskIds []uint8,
	taskMp map[int]api_models.TaskById,
	rewards []*api_models.GetTaskRewardList,
	err error,
) {
	//签到任务
	tasks, err := db_main.GetTaskByType(uint8(utils2.CHECK_IN_TASK))
	if err != nil {
		return
	}
	taskIds = []uint8{}
	taskMp = map[int]api_models.TaskById{}
	for k, v := range tasks {
		taskIds = append(taskIds, uint8(v.Id))
		taskMp[int(v.Id)] = tasks[k]
	}
	if len(taskIds) > 0 {
		rewards, err = db_main.GetTaskRewardListByIds3(taskIds)
		if err != nil {
			return
		}

		var propsIds []int
		for _, v := range rewards {
			if v.RewardType == uint8(utils2.REWARD_TYPE_PROP) && v.PropsId > 0 {
				propsIds = append(propsIds, int(v.PropsId))
			}
		}
		if len(propsIds) > 0 {
			var props []*api_models.Props
			props, err = db_main.GetPropsParam(map[string]interface{}{"id": map[string]interface{}{"in": propsIds}}, "id desc")
			if err != nil {
				return
			}
			propMp := map[int]api_models.Props{}
			for k, v := range props {
				propMp[v.Id] = *props[k]
			}

			for k, v := range rewards {
				if v.RewardType == uint8(utils2.REWARD_TYPE_PROP) {
					props, ok := propMp[int(v.PropsId)]
					if ok {
						rewards[k].Icon = props.Icon
						rewards[k].Title = props.Name
					}
				}
			}
		}
	}

	return
}

/**
 * @author Jared
 * @description 计算组合奖励
 * @createTime 16:53 2022/10/22
 **/
func CalRewardDesc(
	continuous int,
	taskIds []uint8,
	taskMp map[int]api_models.TaskById,
	rewards []*api_models.GetTaskRewardList,
) (*pb.GetTaskRewardList, []*pb.GetTaskRewardList) {
	var newRewards []*api_models.GetTaskRewardList
	var pbRewards []*pb.GetTaskRewardList
	var expPbReward pb.GetTaskRewardList

	if len(taskIds) > 0 {
		for k, v := range rewards {
			task, ok := taskMp[v.TaskId]
			if ok && (continuous == int(task.Frequency)) {
				newRewards = append(newRewards, rewards[k])
			}
		}
	}

	genPbReward := func(pbReward *pb.GetTaskRewardList, v api_models.GetTaskRewardList, title string) *pb.GetTaskRewardList {
		if pbReward == nil {
			pbReward = &pb.GetTaskRewardList{
				TaskId:     0,
				RewardType: uint32(v.RewardType),
				GiftId:     0,
				Icon:       v.Icon,
				Title:      title,
				Quantity:   v.Quantity,
				PropsId:    0,
			}
		} else {
			pbReward.Title = title
			pbReward.Quantity += v.Quantity
		}
		return pbReward
	}

	var diamondPbReward *pb.GetTaskRewardList
	var goldPbReward *pb.GetTaskRewardList
	var nobleExpPbReward *pb.GetTaskRewardList
	var lotteryNumPbReward *pb.GetTaskRewardList
	for _, v := range newRewards {
		if v.Quantity <= 0 {
			continue
		}
		switch utils2.RewardType(v.RewardType) {
		case utils2.REWARD_TYPE_EXP: //奖励用户经验
			expPbReward.Title = "经验"
			expPbReward.Quantity += v.Quantity
		case utils2.REWARD_TYPE_GOLD: //奖励用户鹰钻
			goldPbReward = genPbReward(goldPbReward, *v, "龙币")
		case utils2.REWARD_TYPE_DIAMOND: //奖励用户克拉
			diamondPbReward = genPbReward(diamondPbReward, *v, "龙钻")
		case utils2.REWARD_TYPE_GIFT: //物品奖励
			pbRewards = append(pbRewards, &pb.GetTaskRewardList{
				TaskId:     uint32(v.TaskId),
				RewardType: uint32(v.RewardType),
				GiftId:     uint32(v.GiftId),
				Icon:       v.Icon,
				Title:      v.Title,
				Quantity:   v.Quantity,
			})
		case utils2.REWARD_TYPE_NOBLE_EXPERIENCE_DAY: //贵族卡
			nobleExpPbReward = genPbReward(nobleExpPbReward, *v, "贵族卡")
		case utils2.REWARD_TYPE_PROP: //道具奖励
			pbRewards = append(pbRewards, &pb.GetTaskRewardList{
				TaskId:     uint32(v.TaskId),
				RewardType: uint32(v.RewardType),
				PropsId:    uint32(v.PropsId),
				Icon:       v.Icon,
				Title:      v.Title,
				Quantity:   v.Quantity,
			})
		case utils2.REWARD_TYPE_LOTTERY_FREE_NUM: //抽奖次数
			lotteryNumPbReward = genPbReward(lotteryNumPbReward, *v, "抽奖次数")
		}
	}
	if goldPbReward != nil {
		pbRewards = append(pbRewards, goldPbReward)
	}
	if diamondPbReward != nil {
		pbRewards = append(pbRewards, diamondPbReward)
	}
	if nobleExpPbReward != nil {
		pbRewards = append(pbRewards, nobleExpPbReward)
	}
	if lotteryNumPbReward != nil {
		pbRewards = append(pbRewards, lotteryNumPbReward)
	}

	return &expPbReward, pbRewards
}

/**
 * @author Jared
 * @description 签到方法
 * @createTime 16:52 2022/10/22
 **/
func DoCheckin(uid, continuous, continuousTotal int, checkin *models_main.UserCheckin) (*pb.CheckinResp, error) {
	taskIds, taskMp, rewards, err := GetCheckinTaskReward()
	if err != nil {
		return nil, err
	}
	continuous++
	continuousTotal++
	expPbReward, pbRewards := CalRewardDesc(continuous, taskIds, taskMp, rewards)
	pbRewards = append([]*pb.GetTaskRewardList{expPbReward}, pbRewards...)
	v, _ := json.Marshal(pbRewards)
	history := models_main.UserCheckinHistory{
		Uid:         uid,
		OrdNum:      checkin.OrdNum,
		RewardDesc:  string(v),
		CheckinTime: time.Now(),
	}

	err = global2.GetX().Transaction(func(tx *gorm.DB) error {
		err := db_main.InsertUserCheckinHistory(tx, &history)
		if err != nil {
			return err
		}

		checkin.Count++
		checkin.Continuous = continuousTotal
		fields := []string{
			"continuous",
			"count",
		}
		if continuous == 1 {
			checkin.LastCheckTime = time.Now()
			fields = append(fields, "last_check_time")
		}
		if continuousTotal == 1 {
			checkin.LastCheckStartTime = time.Now()
			fields = append(fields, "last_check_start_time")
		}
		if continuous == WEEKDAY {
			checkin.OrdNum++
			fields = append(fields, "ord_num")
		}
		return db_main.UpdateUserCheckinByTransactions(tx, fields, checkin)
	})
	if err != nil {
		return nil, err
	}

	utils.SafeGo(func() {
		AfterCheckin(CheckinInfo{
			Uid:        uid,
			TaskIds:    taskIds,
			TaskMp:     taskMp,
			Continuous: continuous,
		})
	})
	return &pb.CheckinResp{
		IsSucceed:  true,
		Continuous: uint32(continuous),
		RewardList: pbRewards,
	}, nil
}

/**
 * @author Jared
 * @description 初始化周签到数组
 * @createTime 16:51 2022/10/22
 **/
func GenCheckinDetails() []*pb.CheckinDetail {
	var res []*pb.CheckinDetail
	for i := 0; i < len(expMap); i++ {
		res = append(res, &pb.CheckinDetail{
			Index:      uint32(i + 1),
			IsChecked:  false,
			ExpNum:     0,
			RewardNum:  0,
			RewardList: []*pb.GetTaskRewardList{},
		})
	}
	return res
}

/**
 * @author Jared
 * @description 计算连续签到天数
 * @createTime 16:50 2022/10/22
 **/
func CalContinuous(checkin *models_main.UserCheckin) (int, int, bool, error) {
	history, err := db_main.GetUserCheckinHistoryWeek(checkin.Uid)
	if err != nil {
		return 0, 0, false, err
	}
	timeCompareFunc := func(t1, t2 time.Time) bool {
		if t1.Year() == t2.Year() &&
			t1.YearDay() == t2.YearDay() {
			return true
		}
		return false
	}

	var ordHist, preHist []models_main.UserCheckinHistory
	var isCheckedToday bool
	var isBreakOff bool = true
	for k, v := range history {
		if v.OrdNum == checkin.OrdNum {
			ordHist = append(ordHist, history[k])
		}
		if v.OrdNum == checkin.OrdNum-1 {
			preHist = append(preHist, history[k])
		}
		if timeCompareFunc(v.CheckinTime, time.Now()) {
			isCheckedToday = true
		}
		//判断昨天有没有签到来判断是否中断签到
		if timeCompareFunc(v.CheckinTime, time.Now().AddDate(0, 0, -1)) {
			isBreakOff = false
		}
	}

	//连续累计签到天数
	var continuousTotal = func() int {
		i := checkin.Continuous
		if checkin.LastCheckStartTime.IsZero() {
			return 0
		}
		if checkin.Count <= 0 {
			return 0
		}
		//如果中断签到, 连续签到计数从0开始
		if isBreakOff {
			checkin.LastCheckStartTime = time.Now()
			return 0
		}
		i = int(time.Now().Sub(checkin.LastCheckStartTime) / (24 * time.Hour))
		if isCheckedToday {
			i++
		}
		return i
	}()

	calContinuousFunc := func(arr []models_main.UserCheckinHistory) int {
		var continuous = 0
		if len(arr) > 0 {
			stTime := time.Now()
			if timeCompareFunc(stTime, arr[0].CheckinTime) {
				continuous++
				arr = arr[1:]
			}
			stTime = stTime.AddDate(0, 0, -1)
			for i := 0; i < WEEKDAY-1 && i < len(arr); i++ {
				if timeCompareFunc(stTime.AddDate(0, 0, -i), arr[i].CheckinTime) {
					continuous++
					continue
				}
				break
			}
		}
		return continuous
	}

	if len(ordHist) == 0 && len(preHist) == WEEKDAY {
		continuous := calContinuousFunc(preHist)
		//判断今天是否是一个周循环的第7天, 如果是第7天需要完整显示这7天的记录
		//如果是第二个周循环的第一天则显示签到从0开始
		if continuous == WEEKDAY && timeCompareFunc(checkin.LastCheckTime.AddDate(0, 0, continuous-1), time.Now()) {
			return WEEKDAY, continuousTotal, isCheckedToday, nil
		}
		return 0, continuousTotal, isCheckedToday, nil
	}

	continuous := calContinuousFunc(ordHist)
	return continuous, continuousTotal, isCheckedToday, nil
}

/**
 * @author Jared
 * @description 装配签到奖励到周签到数组
 * @createTime 16:51 2022/10/22
 **/
func GetMarkedDetails(continuous int) ([]*pb.CheckinDetail, error) {
	taskIds, taskMp, rewards, err := GetCheckinTaskReward()
	if err != nil {
		return nil, err
	}

	checkinDetail := GenCheckinDetails()
	for k, v := range checkinDetail {
		if int(v.Index) <= continuous {
			checkinDetail[k].IsChecked = true
		}
		expPbReward, pbRewards := CalRewardDesc(int(v.Index), taskIds, taskMp, rewards)
		checkinDetail[k].ExpNum = expPbReward.Quantity
		checkinDetail[k].RewardNum = uint32(len(pbRewards))
		sort.Slice(pbRewards, func(i, j int) bool {
			return pbRewards[i].RewardType < pbRewards[j].RewardType
		})
		checkinDetail[k].RewardList = pbRewards
	}

	return checkinDetail, nil
}

type CheckinInfo struct {
	Uid        int
	TaskIds    []uint8                     //条件签到任务id
	TaskMp     map[int]api_models.TaskById //任务记录
	Continuous int                         //累计签到天数
}

/**
 * @author Jared
 * @description 签到后事件处理
 * @createTime 16:57 2022/10/22
 **/
func AfterCheckin(info CheckinInfo) {
	//完成签到任务消息
	DoTaskComplete(info)
	//持久化签到统计
	DoCheckinStatistic(info)
}

func DoTaskComplete(info CheckinInfo) {
	time.Sleep(time.Second)
	for _, v := range info.TaskIds {
		task, ok := info.TaskMp[int(v)]
		if ok && (info.Continuous == int(task.Frequency)) {
			err := cache.OnTaskEvent(info.Uid, utils2.TaskId(v), int(task.Frequency))
			if err != nil {
				global2.Log.Error(fmt.Sprintf(
					"签到奖励: 条件签到任务推送异常, uid:%d, date:%s ,taskId: %d",
					info.Uid,
					time.Now().Format(time2.TIME_LAYOUT_FORMAT_4),
					v,
				), err)
				return
			}
			time.Sleep(time.Second)
		}
	}
}

func DoCheckinStatistic(info CheckinInfo) {
	//todo
	//当前天数统计人数-1, 当前天数+1后的统计人数+1
}
